package com.wingsoft.homeFlow.service.impl;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.db.DbUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.wingsoft.common.enums.SwitchEnum;
import com.wingsoft.common.exception.ServiceException;
import com.wingsoft.common.utils.DateUtils;
import com.wingsoft.common.utils.SecurityUtils;
import com.wingsoft.common.utils.bean.BeanConvertUtils;
import com.wingsoft.common.utils.spring.SpringUtils;
import com.wingsoft.homeFlow.bo.*;
import com.wingsoft.homeFlow.entity.HomeFlowSource;
import com.wingsoft.homeFlow.entity.HomeFlowTaskStep;
import com.wingsoft.homeFlow.mapper.HomeFlowTaskStepMapper;
import com.wingsoft.homeFlow.service.HomeFlowSourceService;
import com.wingsoft.homeFlow.service.HomeFlowTaskService;
import com.wingsoft.homeFlow.service.HomeFlowTaskStepService;
import com.wingsoft.homeFlow.service.HomeFlowTaskVarService;
import com.wingsoft.homeFlow.utils.DbUtils;
import com.wingsoft.homeFlow.utils.VelocityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.message.Message;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.namespace.QName;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Wingsoft
 * @description 针对表【HOME_FLOW_TASK_STEP(流水线任务步骤)】的数据库操作Service实现
 * @createDate 2025-06-04 12:48:30
 */
@Slf4j
@Service
public class HomeFlowTaskStepServiceImpl extends ServiceImpl<HomeFlowTaskStepMapper, HomeFlowTaskStep> implements HomeFlowTaskStepService {
    @Autowired
    private HomeFlowSourceService homeFlowSourceService;
    @Autowired
    private HomeFlowTaskService homeFlowTaskService;
    @Autowired
    private HomeFlowTaskVarService homeFlowTaskVarService;

    public static final String SQL_RESULT_KEY = "sqlResult";

    @Transactional
    @Override
    public void add(HomeFlowTaskStepAddBo homeFlowTaskStepAddBo) {
        String taskCode = homeFlowTaskStepAddBo.getTaskCode();
        if (StringUtils.isBlank(taskCode)) {
            throw new ServiceException("任务编码 不能为空");
        }
        String stepName = homeFlowTaskStepAddBo.getStepName();
        if (StringUtils.isBlank(stepName)) {
            throw new ServiceException("步骤名称 不能为空");
        }
        String stepCode = homeFlowTaskStepAddBo.getStepCode();
        if (StringUtils.isBlank(stepCode)) {
            throw new ServiceException("步骤KEY 不能为空");
        }
        if (!Objects.equals(homeFlowTaskStepAddBo.getInteractionType(), HomeFlowTaskStepBo.InteractionTypeEnum.THIRD_CALL_US_API.getCode())) {
            String sourceId = homeFlowTaskStepAddBo.getSourceId();
            if (StringUtils.isBlank(sourceId)) {
                throw new ServiceException("数据源ID 不能为空");
            }
            Integer respDataType = homeFlowTaskStepAddBo.getRespDataType();
            if (Objects.nonNull(respDataType)) {
                HomeFlowTaskStepBo.RespDataTypeEnum.getEnumByCode(respDataType);
            }
            Integer stepType = homeFlowTaskStepAddBo.getStepType();
            if (Objects.isNull(stepType)) {
                throw new ServiceException("步骤类型 不能为空");
            } else {
                HomeFlowTaskStepBo.StepTypeEnum.getEnumByCode(stepType);
            }
        }
        Integer stepIndex = homeFlowTaskStepAddBo.getStepIndex();
        if (Objects.isNull(stepIndex)) {
            List<HomeFlowTaskStep> homeFlowTaskStepList = this.listByTaskCode(taskCode);
            Optional<HomeFlowTaskStep> max = homeFlowTaskStepList.stream().max(Comparator.comparingInt(HomeFlowTaskStep::getStepIndex));
            if (max.isPresent()) {
                HomeFlowTaskStep homeFlowTaskStep = max.get();
                homeFlowTaskStepAddBo.setStepIndex(homeFlowTaskStep.getStepIndex() + 1);
            } else {
                homeFlowTaskStepAddBo.setStepIndex(1);
            }
        } else {
            List<HomeFlowTaskStep> homeFlowTaskStepList = this.listByTaskCode(taskCode);
            if (homeFlowTaskStepList.stream().anyMatch(o -> Objects.equals(o.getStepIndex(), stepIndex))) {
                throw new ServiceException("步骤顺序 重复");
            }
        }
        Integer isUsed = homeFlowTaskStepAddBo.getIsUsed();
        if (Objects.isNull(isUsed)) {
            homeFlowTaskStepAddBo.setIsUsed(SwitchEnum.TRUE.getCode());
        }
        List<HomeFlowTaskStep> list = this.list(new LambdaQueryWrapper<HomeFlowTaskStep>() {{
            eq(HomeFlowTaskStep::getTaskCode, taskCode);
        }});
        if (CollectionUtils.isNotEmpty(list) && list.stream().anyMatch(item -> Objects.equals(item.getStepCode(), stepCode))) {
            throw new ServiceException("步骤KEY 已存在");
        }
        Integer interactionType = homeFlowTaskStepAddBo.getInteractionType();
        HomeFlowTaskStepBo.InteractionTypeEnum interactionTypeEnum = HomeFlowTaskStepBo.InteractionTypeEnum.getEnumByCode(interactionType);
        if (Objects.equals(interactionTypeEnum, HomeFlowTaskStepBo.InteractionTypeEnum.THIRD_CALL_US_API)) {
            if (CollectionUtils.isNotEmpty(list)) {
                throw new ServiceException("第三方调用我们接口，一个流水线仅能配置一次，且必须在第一步");
            } else {
                homeFlowTaskService.updateTaskDirectionTypeByTaskCode(taskCode, HomeFlowTaskBo.TaskDirectionTypeEnum.THIRD_CALL_US.getCode());
            }
        } else {
            homeFlowTaskService.updateTaskDirectionTypeByTaskCode(taskCode, HomeFlowTaskBo.TaskDirectionTypeEnum.WE_CALL_THIRD.getCode());
        }
        Date date = new Date();
        Long userId = SecurityUtils.getUserId();
        if (!this.save(BeanConvertUtils.convert(homeFlowTaskStepAddBo, HomeFlowTaskStep.class, (s, t) -> {
            t.setCreateUserId(userId);
            t.setCreateTime(date);
            t.setUpdateUserId(userId);
            t.setUpdateTime(date);
        }))) {
            throw new ServiceException("新增失败");
        }

        List<HomeFlowTaskVarAddBo> homeFlowTaskVarAddBoList = homeFlowTaskStepAddBo.getHomeFlowTaskVarAddBoList();
        for (HomeFlowTaskVarAddBo homeFlowTaskVarAddBo : homeFlowTaskVarAddBoList) {
            homeFlowTaskVarAddBo.setTaskCode(taskCode);
            homeFlowTaskVarAddBo.setStepCode(stepCode);
        }
        homeFlowTaskVarService.addNotManualList(homeFlowTaskVarAddBoList);
    }

    @Transactional
    @Override
    public void uptStatusById(HomeFlowTaskStepUptBo homeFlowTaskStepUptBo) {
        String id = homeFlowTaskStepUptBo.getId();
        if (StringUtils.isBlank(id)) {
            throw new ServiceException("ID 不能为空");
        }
        Integer isUsed = homeFlowTaskStepUptBo.getIsUsed();
        if (Objects.isNull(isUsed)) {
            throw new ServiceException("是否启用 不能为空");
        } else {
            SwitchEnum.getEnumByCode(isUsed);
        }
        Long userId = SecurityUtils.getUserId();
        if (!this.updateById(new HomeFlowTaskStep() {{
            setId(id);
            setIsUsed(homeFlowTaskStepUptBo.getIsUsed());
            setUpdateUserId(userId);
            setUpdateTime(new Date());
        }})) {
            throw new ServiceException("修改失败");
        }
    }

    @Transactional
    @Override
    public void uptById(HomeFlowTaskStepUptBo homeFlowTaskStepUptBo) {
        String id = homeFlowTaskStepUptBo.getId();
        if (StringUtils.isBlank(id)) {
            throw new ServiceException("ID 不能为空");
        }
        String taskCode = homeFlowTaskStepUptBo.getTaskCode();
        if (StringUtils.isBlank(taskCode)) {
            throw new ServiceException("任务编码 不能为空");
        }
        String stepName = homeFlowTaskStepUptBo.getStepName();
        if (StringUtils.isBlank(stepName)) {
            throw new ServiceException("步骤名称 不能为空");
        }
        String stepCode = homeFlowTaskStepUptBo.getStepCode();
        if (StringUtils.isBlank(stepCode)) {
            throw new ServiceException("步骤KEY 不能为空");
        }
        if (!Objects.equals(homeFlowTaskStepUptBo.getInteractionType(), HomeFlowTaskStepBo.InteractionTypeEnum.THIRD_CALL_US_API.getCode())) {
            String sourceId = homeFlowTaskStepUptBo.getSourceId();
            if (StringUtils.isBlank(sourceId)) {
                throw new ServiceException("数据源ID 不能为空");
            }
            Integer respDataType = homeFlowTaskStepUptBo.getRespDataType();
            if (Objects.nonNull(respDataType)) {
                HomeFlowTaskStepBo.RespDataTypeEnum.getEnumByCode(respDataType);
            }
            Integer stepType = homeFlowTaskStepUptBo.getStepType();
            if (Objects.isNull(stepType)) {
                throw new ServiceException("步骤类型 不能为空");
            } else {
                HomeFlowTaskStepBo.StepTypeEnum.getEnumByCode(stepType);
            }
        }
        Integer stepIndex = homeFlowTaskStepUptBo.getStepIndex();
        if (Objects.isNull(stepIndex)) {
            List<HomeFlowTaskStep> homeFlowTaskStepList = this.listByTaskCode(taskCode);
            Optional<HomeFlowTaskStep> max = homeFlowTaskStepList.stream().max(Comparator.comparingInt(HomeFlowTaskStep::getStepIndex));
            if (max.isPresent()) {
                HomeFlowTaskStep homeFlowTaskStep = max.get();
                homeFlowTaskStepUptBo.setStepIndex(homeFlowTaskStep.getStepIndex() + 1);
            } else {
                homeFlowTaskStepUptBo.setStepIndex(1);
            }
        } else {
            List<HomeFlowTaskStep> homeFlowTaskStepList = this.listByTaskCode(taskCode);
            if (homeFlowTaskStepList.stream().anyMatch(
                    o -> Objects.equals(o.getStepIndex(), stepIndex)
                            && !Objects.equals(o.getId(), id)
            )) {
                throw new ServiceException("步骤顺序 重复");
            }
        }
        Integer isUsed = homeFlowTaskStepUptBo.getIsUsed();
        if (Objects.isNull(isUsed)) {
            homeFlowTaskStepUptBo.setIsUsed(SwitchEnum.TRUE.getCode());
        }
        List<HomeFlowTaskStep> list = this.list(new LambdaQueryWrapper<HomeFlowTaskStep>() {{
            eq(HomeFlowTaskStep::getTaskCode, taskCode);
            ne(HomeFlowTaskStep::getId, id);
        }});
        if (CollectionUtils.isNotEmpty(list) && list.stream().anyMatch(item -> Objects.equals(item.getStepCode(), stepCode))) {
            throw new ServiceException("步骤KEY 已存在");
        }
        Integer interactionType = homeFlowTaskStepUptBo.getInteractionType();
        HomeFlowTaskStepBo.InteractionTypeEnum interactionTypeEnum = HomeFlowTaskStepBo.InteractionTypeEnum.getEnumByCode(interactionType);
        if (Objects.equals(interactionTypeEnum, HomeFlowTaskStepBo.InteractionTypeEnum.THIRD_CALL_US_API)) {
            if (CollectionUtils.isNotEmpty(list) && list.stream().anyMatch(o -> Objects.equals(HomeFlowTaskStepBo.InteractionTypeEnum.THIRD_CALL_US_API.getCode(), o.getInteractionType()))) {
                throw new ServiceException("第三方调用我们接口，一个流水线仅能配置一次，且必须在第一步");
            } else {
                homeFlowTaskService.updateTaskDirectionTypeByTaskCode(taskCode, HomeFlowTaskBo.TaskDirectionTypeEnum.WE_CALL_THIRD.getCode());
            }
        } else {
            homeFlowTaskService.updateTaskDirectionTypeByTaskCode(taskCode, HomeFlowTaskBo.TaskDirectionTypeEnum.WE_CALL_THIRD.getCode());
        }
        HomeFlowTaskStep homeFlowTaskStep = this.getById(id);
        if (Objects.isNull(homeFlowTaskStep)) {
            throw new ServiceException("流水线任务步骤不存在");
        }
        HomeFlowTaskStep homeFlowTaskStepUpt = BeanConvertUtils.convert(homeFlowTaskStepUptBo, HomeFlowTaskStep.class);
        homeFlowTaskStepUpt.setUpdateTime(new Date());
        homeFlowTaskStepUpt.setUpdateUserId(SecurityUtils.getUserId());
        if (!this.update(homeFlowTaskStepUpt, new LambdaUpdateWrapper<HomeFlowTaskStep>() {{
            eq(HomeFlowTaskStep::getId, homeFlowTaskStepUptBo.getId());
            set(ObjectUtils.isEmpty(homeFlowTaskStepUptBo.getRespDataType()), HomeFlowTaskStep::getRespDataType, homeFlowTaskStepUptBo.getRespDataType());
        }})) {
            throw new ServiceException("修改失败");
        }

        homeFlowTaskVarService.uptNotManualListById(taskCode, stepCode, homeFlowTaskStepUptBo.getHomeFlowTaskVarUptBoList());
    }

    @Transactional
    @Override
    public void delById(String id) {
        if (StringUtils.isBlank(id)) {
            throw new ServiceException("ID 不能为空");
        }
        HomeFlowTaskStep homeFlowTaskStep = this.getById(id);
        if (Objects.isNull(homeFlowTaskStep)) {
            throw new ServiceException("流水线任务步骤不存在");
        }
        if (!this.removeById(id)) {
            throw new ServiceException("删除失败");
        }
        homeFlowTaskVarService.delByStepCode(homeFlowTaskStep.getTaskCode(), homeFlowTaskStep.getStepCode());
        List<HomeFlowTaskStep> homeFlowTaskStepList = this.listByTaskCode(homeFlowTaskStep.getTaskCode());
        if (CollectionUtils.isEmpty(homeFlowTaskStepList)) {
            homeFlowTaskService.updateTaskDirectionTypeByTaskCode(homeFlowTaskStep.getTaskCode(), null);
        }
    }

    @Override
    public HomeFlowTaskStepVo getVoById(String id) {
        HomeFlowTaskStepVo homeFlowTaskStepVo = BeanConvertUtils.convert(this.getById(id), HomeFlowTaskStepVo.class);
        this.handleHomeFlowTaskStepVoList(homeFlowTaskStepVo.getTaskCode(), Collections.singletonList(homeFlowTaskStepVo));
        return homeFlowTaskStepVo;
    }

    @Override
    public List<HomeFlowTaskStepVo> listVoByTaskCode(String taskCode) {
        List<HomeFlowTaskStepVo> homeFlowTaskStepVoList = BeanConvertUtils.convertList(this.listByTaskCode(taskCode), HomeFlowTaskStepVo.class);
        this.handleHomeFlowTaskStepVoList(taskCode, homeFlowTaskStepVoList);
        return homeFlowTaskStepVoList;
    }

    @Override
    public List<HomeFlowTaskStep> listByTaskCode(String taskCode) {
        return this.list(new LambdaQueryWrapper<HomeFlowTaskStep>() {{
            eq(HomeFlowTaskStep::getTaskCode, taskCode);
            eq(HomeFlowTaskStep::getIsUsed, SwitchEnum.TRUE.getCode());
            orderByAsc(HomeFlowTaskStep::getStepIndex);
        }});
    }

    @Override
    public Page<HomeFlowTaskStepVo> page(HomeFlowTaskStepQo homeFlowTaskStepQo) {
        String id = homeFlowTaskStepQo.getId();
        String taskCode = homeFlowTaskStepQo.getTaskCode();
        if (StringUtils.isBlank(taskCode)) {
            throw new ServiceException("任务编码 不能为空");
        }
        String stepName = homeFlowTaskStepQo.getStepName();
        Integer interactionType = homeFlowTaskStepQo.getInteractionType();
        String stepCode = homeFlowTaskStepQo.getStepCode();
        Integer pageNum = homeFlowTaskStepQo.getPageNum();
        Integer pageSize = homeFlowTaskStepQo.getPageSize();

        Page<HomeFlowTaskStep> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<HomeFlowTaskStep> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(id)) {
            queryWrapper.eq(HomeFlowTaskStep::getId, id);
        }
        if (StringUtils.isNotBlank(taskCode)) {
            queryWrapper.eq(HomeFlowTaskStep::getTaskCode, taskCode);
        }
        if (StringUtils.isNotBlank(stepName)) {
            queryWrapper.eq(HomeFlowTaskStep::getStepName, stepName);
        }
        if (Objects.nonNull(interactionType)) {
            queryWrapper.eq(HomeFlowTaskStep::getInteractionType, interactionType);
        }
        if (StringUtils.isNotBlank(stepCode)) {
            queryWrapper.eq(HomeFlowTaskStep::getStepCode, stepCode);
        }
        queryWrapper.eq(HomeFlowTaskStep::getIsUsed, SwitchEnum.TRUE.getCode());

        queryWrapper.orderByAsc(HomeFlowTaskStep::getStepIndex);
        queryWrapper.orderByAsc(HomeFlowTaskStep::getCreateTime);
        page.setOptimizeCountSql(false);
        Page<HomeFlowTaskStep> homeFlowTaskPage = this.page(page, queryWrapper);
        List<HomeFlowTaskStepVo> homeFlowTaskStepVoList = BeanConvertUtils.convertList(homeFlowTaskPage.getRecords(), HomeFlowTaskStepVo.class);
        this.handleHomeFlowTaskStepVoList(taskCode, homeFlowTaskStepVoList);
        return BeanConvertUtils.convert(homeFlowTaskPage, Page.class, (s, t) -> {
            t.setRecords(homeFlowTaskStepVoList);
        });
    }

    private void handleHomeFlowTaskStepVoList(String taskCode, List<HomeFlowTaskStepVo> homeFlowTaskStepVoList) {
        List<HomeFlowTaskVarVo> homeFlowTaskVarVoList = BeanConvertUtils.convertList(homeFlowTaskVarService.listByTaskCode(taskCode), HomeFlowTaskVarVo.class);
        Map<String, HomeFlowTaskVarVo> varMap = homeFlowTaskVarVoList.stream()
                .collect(Collectors.toMap(HomeFlowTaskVarVo::getVarCodeFull, Function.identity(), (a, b) -> b));
        for (HomeFlowTaskStepVo homeFlowTaskStepVo : homeFlowTaskStepVoList) {
            Set<String> varCodeSet = new HashSet<>();
            List<String> varCodeList = VelocityUtils.getVarCodeList(
                    homeFlowTaskStepVo.getReqHeader() +
                            homeFlowTaskStepVo.getReqForm() +
                            homeFlowTaskStepVo.getReqTemplate() +
                            homeFlowTaskStepVo.getReqBody()
            );
            if (CollectionUtils.isNotEmpty(varCodeList)) {
                varCodeSet.addAll(varCodeList);
            }
            List<HomeFlowTaskVarVo> reqHomeFlowTaskVarVoList = new ArrayList<>();
            for (String key : varCodeSet) {
                HomeFlowTaskVarVo homeFlowTaskVarVo = varMap.get(key);
                if (Objects.nonNull(homeFlowTaskVarVo)) {
                    reqHomeFlowTaskVarVoList.add(homeFlowTaskVarVo);
                }
            }
            homeFlowTaskStepVo.setReqHomeFlowTaskVarVoList(reqHomeFlowTaskVarVoList);
            homeFlowTaskStepVo.setRespHomeFlowTaskVarVoList(homeFlowTaskVarVoList.stream()
                    .filter(o -> Objects.equals(o.getStepCode(), homeFlowTaskStepVo.getStepCode()))
                    .filter(o -> Objects.equals(o.getManualFlag(), SwitchEnum.FALSE.getCode()))
                    .collect(Collectors.toList()));
        }
    }

    @Override
    public List<String> parseRespVarPath(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo) {
        HomeFlowTaskStepBo homeFlowTaskStepBo = homeFlowTaskStepExecBo.getHomeFlowTaskStepBo();
        Object object = null;
        if (Objects.equals(HomeFlowTaskStepBo.InteractionTypeEnum.DATABASE.getCode(), homeFlowTaskStepBo.getInteractionType())) {
            homeFlowTaskStepBo.setRespDataType(HomeFlowTaskStepBo.RespDataTypeEnum.OBJECT.getCode());
        }
        HomeFlowTaskStepBo.StepTypeEnum stepTypeEnum = HomeFlowTaskStepBo.StepTypeEnum.getEnumByCode(homeFlowTaskStepBo.getStepType());
        switch (stepTypeEnum) {
            case SQL:
                if (ObjectUtils.isEmpty(homeFlowTaskStepBo.getReqTemplate())) {
                    return Collections.emptyList();
                } else if (Objects.equals(homeFlowTaskStepBo.getStepType(), HomeFlowTaskStepBo.StepTypeEnum.SQL.getCode())
                        && !homeFlowTaskStepBo.getReqTemplate().toLowerCase().trim().startsWith("select")) {
                    return Collections.emptyList();
                }
                object = this.execTaskStep(homeFlowTaskStepExecBo);
                break;
            case PROCEDURE:
                object = this.execTaskStep(homeFlowTaskStepExecBo);
                break;
            case API:
                try {
                    object = JSONUtil.parseObj(homeFlowTaskStepBo.getRespTemplate());
                } catch (Exception e) {
                    throw new ServiceException("响应模板解析失败");
                }
                break;
        }
        List<String> pathList = new ArrayList<>();
        traverseJson(object, "", pathList);
        return pathList;
    }

    private void traverseJson(Object node, String currentPath, List<String> paths) {
        if (node instanceof JSONObject) {
            JSONObject obj = (JSONObject) node;
            for (String key : obj.keySet()) {
                String newPath = currentPath.isEmpty() ? key : currentPath + "." + key;
                traverseJson(obj.get(key), newPath, paths);
            }
        }
/*        else if (node instanceof JSONArray ) {
            JSONArray array = (JSONArray) node;
            for (int i = 0; i < array.size(); i++) {
                String newPath = currentPath + "[" + i + "]";
                traverseJson(array.get(i), newPath, paths);
            }
        } */
        else {
            // 叶子节点，添加到路径列表
            paths.add(currentPath);
        }
    }

    @Override
    public Object execTaskStep(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo) {
        HomeFlowTaskStepBo homeFlowTaskStepBo = homeFlowTaskStepExecBo.getHomeFlowTaskStepBo();
        Object reqRes = this.doExecTaskStep(homeFlowTaskStepExecBo);
        if (Objects.isNull(reqRes) || ObjectUtils.isEmpty(homeFlowTaskStepBo.getRespDataType())) {
            return null;
        }
        HomeFlowTaskStepBo.RespDataTypeEnum respDataTypeEnum = HomeFlowTaskStepBo.RespDataTypeEnum.getEnumByCode(homeFlowTaskStepBo.getRespDataType());
        Object resultObj = null;
        if (reqRes instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) reqRes;
            JSONObject sqlResult = jsonObject.getJSONObject(SQL_RESULT_KEY);
            if (Objects.nonNull(sqlResult)) {
                Optional<Integer> max = sqlResult.keySet().stream().map(Integer::valueOf).max(Comparator.naturalOrder());
                Integer maxIndex = null;
                if (max.isPresent()) {
                    maxIndex = max.get();
                }
                switch (respDataTypeEnum) {
                    case SINGLE: {
                        JSONArray lastArray = JSONUtil.parseArray(sqlResult.get(String.valueOf(maxIndex)));
                        if (!lastArray.isEmpty()) {
                            JSONObject obj = JSONUtil.parseObj(lastArray.get(0));
                            Optional<String> max1 = obj.keySet().stream().max(Comparator.naturalOrder());
                            if (max1.isPresent()) {
                                resultObj = obj.get(max1.get());
                            }
                        }
                    }
                    break;
                    case OBJECT: {
                        JSONArray lastArray = JSONUtil.parseArray(sqlResult.get(String.valueOf(maxIndex)));
                        if (!lastArray.isEmpty()) {
                            resultObj = lastArray.get(0);
                        }
                    }
                    break;
                    case COLLECTION: {
                        resultObj = JSONUtil.parseArray(sqlResult.get(String.valueOf(maxIndex)));
                    }
                    break;
                    case JSON: {
                        resultObj = sqlResult;
                    }
                    break;
                }
            } else {
                resultObj = reqRes;
            }
        } else {
            resultObj = reqRes;
        }
        return resultObj;
    }

    public Object doExecTaskStep(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo) {
        HomeFlowTaskStepBo homeFlowTaskStepBo = homeFlowTaskStepExecBo.getHomeFlowTaskStepBo();
        Object result = null;
        HomeFlowSource homeFlowSource = homeFlowSourceService.getById(homeFlowTaskStepBo.getSourceId());
        if (Objects.isNull(homeFlowSource)) {
            throw new ServiceException("数据源不存在");
        }
        HomeFlowTaskStepBo.StepTypeEnum stepTypeEnum = HomeFlowTaskStepBo.StepTypeEnum.getEnumByCode(homeFlowTaskStepBo.getStepType());
        switch (stepTypeEnum) {
            case SQL:
                result = execSql(homeFlowTaskStepExecBo, homeFlowSource);
                break;
            case PROCEDURE:
                result = execProcedure(homeFlowTaskStepExecBo, homeFlowSource);
                break;
            case API:
                result = execApi(homeFlowTaskStepExecBo, homeFlowSource);
                break;
            case BEAN:
                result = execBean(homeFlowTaskStepExecBo);
                break;
        }
        return result;
    }

    private JSONObject execSql(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo, HomeFlowSource homeFlowSource) {
        HomeFlowTaskStepBo homeFlowTaskStepBo = homeFlowTaskStepExecBo.getHomeFlowTaskStepBo();
        JSONObject result = new JSONObject();
        VelocityUtils.VelocityResult velocityResult = VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqTemplate(), homeFlowTaskStepExecBo.getParamMap(), true);
        String maskTemplate = velocityResult.getTemplate();
        List<Object> varValueList = velocityResult.getVarValueList();
        HomeFlowTaskExecTaskStepLogVo stepLog = homeFlowTaskStepExecBo.getStepLog();
        HomeFlowTaskExecTaskStepLogVo.ExecContent execContent = stepLog.getExecContent();
        execContent.setStepType(homeFlowTaskStepBo.getStepType());
        execContent.setReqMethod(homeFlowTaskStepBo.getReqMethod());
        execContent.setReqTemplate(maskTemplate);
        for (Object object : varValueList) {
            if (object instanceof String) {
                execContent.setReqTemplate(execContent.getReqTemplate().replaceFirst("\\?", "'" + object + "'"));
            } else {
                execContent.setReqTemplate(execContent.getReqTemplate().replaceFirst("\\?", String.valueOf(object)));
            }
        }
        Connection connection;
        if (maskTemplate.startsWith("singleConnection")) {
            maskTemplate = maskTemplate.replaceFirst("singleConnection", "").trim();
            connection = DbUtils.getSingleConnection(homeFlowSource);
        } else {
            connection = DbUtils.getConnection(homeFlowSource);
        }
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection.setAutoCommit(false);
            String[] splitSql = maskTemplate.split(DbUtils.SPLIT_CHAR);
            List<Object> varList = new ArrayList<>(velocityResult.getVarValueList());
            JSONObject sqlResult = new JSONObject();
            for (int sqlIndex = 0; sqlIndex < splitSql.length; sqlIndex++) {
                String sql = splitSql[sqlIndex].trim();
                if (ObjectUtils.isEmpty(sql)) {
                    continue;
                }
                boolean ignoreError = false;
                if (sql.startsWith("ignoreError")) {
                    sql = sql.replaceFirst("ignoreError", "").trim();
                    ignoreError = true;
                }
                try {
                    preparedStatement = connection.prepareStatement(sql);
                    List<Object> removeList = new ArrayList<>();
                    List<Byte> byteList = new ArrayList<>();
                    for (byte b : sql.getBytes()) {
                        byteList.add(b);
                    }
                    long count = byteList.stream().filter(e -> Objects.equals(e, "?".getBytes()[0])).count();
                    for (int i = 1; i <= count; i++) {
                        Object object = varList.get(i - 1);
                        DbUtils.containsSqlInjection(object);
                        if (object instanceof Date) {
                            object = DateUtils.dateToLocalDateTime((Date) object);
                        }
                        preparedStatement.setObject(i, object);
                        removeList.add(object);
                    }
                    varList.removeAll(removeList);
                    if (preparedStatement.execute()) {
                        resultSet = preparedStatement.getResultSet();
                        if (ObjectUtils.isNotEmpty(resultSet)) {
                            // 获取结果集元数据
                            ResultSetMetaData metaData = resultSet.getMetaData();
                            int columnCount = metaData.getColumnCount();
                            // 处理查询结果
                            JSONArray jsonArray = new JSONArray();
                            while (resultSet.next()) {
                                JSONObject jsonObject = new JSONObject();
                                for (int i = 1; i <= columnCount; i++) {
                                    String columnName = metaData.getColumnName(i);
                                    Object columnValue = resultSet.getObject(i);
                                    if (columnValue instanceof oracle.sql.CLOB) {
                                        columnValue = resultSet.getString(i);
                                    }
                                    jsonObject.set(columnName, columnValue);
                                }
                                jsonArray.set(jsonObject);
                            }
                            sqlResult.set(String.valueOf(sqlIndex + 1), jsonArray);
                        }
                    }
                } catch (Exception e) {
                    if (ignoreError) {
                        log.warn("【已忽略】流水线任务{}步骤{} SQL执行失败：{}", homeFlowTaskStepBo.getTaskCode(), homeFlowTaskStepBo.getStepCode(), sql, e);
                    } else {
                        log.error("流水线任务{}步骤{} SQL执行失败:{}", homeFlowTaskStepBo.getTaskCode(), homeFlowTaskStepBo.getStepCode(), sql, e);
                        throw new ServiceException("流水线任务步骤SQL执行失败");
                    }
                }
            }
            result.set(SQL_RESULT_KEY, sqlResult);
            stepLog.setSuccessFlag(true);
            connection.commit();
        } catch (Exception e) {
            try {
                if (Objects.nonNull(connection)) {
                    connection.rollback();
                }
            } catch (Exception ex) {
                log.error("事务回滚失败", ex);
            }
            log.error("SQL执行失败", e);
            throw new ServiceException("SQL执行失败");
        } finally {
            stepLog.setFinishFlag(true);
            DbUtil.close(resultSet, preparedStatement, connection);
        }
        return result;
    }

    private JSONObject execProcedure(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo, HomeFlowSource homeFlowSource) {
        HomeFlowTaskStepBo homeFlowTaskStepBo = homeFlowTaskStepExecBo.getHomeFlowTaskStepBo();
        JSONObject result = new JSONObject();
        DruidPooledConnection connection = null;
        CallableStatement callableStatement = null;
        ResultSet resultSet = null;
        VelocityUtils.VelocityResult velocityResult = VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqTemplate(), homeFlowTaskStepExecBo.getParamMap(), true);
        String maskTemplate = velocityResult.getTemplate();
        List<Object> varValueList = velocityResult.getVarValueList();
        HomeFlowTaskExecTaskStepLogVo stepLog = homeFlowTaskStepExecBo.getStepLog();
        HomeFlowTaskExecTaskStepLogVo.ExecContent execContent = stepLog.getExecContent();
        execContent.setStepType(homeFlowTaskStepBo.getStepType());
        execContent.setReqMethod(homeFlowTaskStepBo.getReqMethod());
        execContent.setReqTemplate(maskTemplate);
        for (Object object : varValueList) {
            if (object instanceof String) {
                execContent.setReqTemplate(execContent.getReqTemplate().replaceFirst("\\?", "'" + object + "'"));
            } else {
                execContent.setReqTemplate(execContent.getReqTemplate().replaceFirst("\\?", String.valueOf(object)));
            }
        }
        try {
            connection = DbUtils.getConnection(homeFlowSource);
            String splitChar = "/";
            String owner = null;
            String packAndProc = "";
            String packageName = null;
            String procedureName;
            String ownerPackAndProc = maskTemplate.substring(0, maskTemplate.indexOf("("));
            if (maskTemplate.contains(splitChar)) {
                String[] split = ownerPackAndProc.split(splitChar);
                owner = split[0].trim();
                packAndProc = split[1].trim();
            } else {
                packAndProc = ownerPackAndProc;
            }
            String[] packAndProcSplit = packAndProc.split("\\.");
            if (packAndProcSplit.length == 1) {
                procedureName = packAndProcSplit[0];
            } else if (packAndProcSplit.length == 2) {
                packageName = packAndProcSplit[0].trim();
                procedureName = packAndProcSplit[1].trim();
            } else {
                throw new ServiceException("表达式配置不正确");
            }
            StringBuilder exeProc = new StringBuilder("{call ");
            if (ObjectUtils.isNotEmpty(owner)) {
                exeProc.append(owner).append(".");
            }
            if (ObjectUtils.isNotEmpty(packageName)) {
                exeProc.append(packageName).append(".");
            }
            if (ObjectUtils.isNotEmpty(procedureName)) {
                exeProc.append(procedureName);
            }
            String paramsStr = maskTemplate.substring(maskTemplate.indexOf("(") + 1, maskTemplate.indexOf(")"));
            List<Integer> parameterIndexList = new ArrayList<>();
            List<String> outVarCodeList = new ArrayList<>();
            if (ObjectUtils.isNotEmpty(paramsStr)) {
                String[] params = paramsStr.split(",");
                exeProc.append("(");
                for (int i = 0; i < params.length; i++) {
                    exeProc.append("?,");
                }
                exeProc.deleteCharAt(exeProc.length() - 1);
                exeProc.append(")}");
                callableStatement = connection.prepareCall(exeProc.toString());
                for (int i = 0; i < params.length; i++) {
                    String param = params[i];
                    String[] split = param.split(":");
                    String name = split[0].trim();
                    String mode = split[1].trim().toUpperCase();
                    String sqlType = split[2].trim();
                    Object paramValue = null;
                    if (param.contains("?")) {
                        paramValue = varValueList.get(0);
                        varValueList.remove(0);
                    }
                    int parameterIndex = i + 1;
                    if (mode.contains("IN")) {
                        callableStatement.setObject(parameterIndex, paramValue);
                    }
                    if (mode.contains("OUT")) {
                        callableStatement.registerOutParameter(parameterIndex, Integer.parseInt(sqlType));
                        parameterIndexList.add(parameterIndex);
                        outVarCodeList.add(name);
                    }
                }
            } else {
                exeProc.append("()}");
                callableStatement = connection.prepareCall(exeProc.toString());
            }
            callableStatement.execute();
            for (int idx = 0; idx < parameterIndexList.size(); idx++) {
                Integer parameterIndex = parameterIndexList.get(idx);
                String outVarCode = outVarCodeList.get(idx);
                Object object = callableStatement.getObject(parameterIndex);
                if (object instanceof ResultSet) {
                    ResultSet rs = (ResultSet) object;
                    ResultSetMetaData metaData = rs.getMetaData();
                    int columnCount = metaData.getColumnCount();
                    JSONArray jsonArray = new JSONArray();
                    while (rs.next()) {
                        JSONObject instance = new JSONObject();
                        for (int i = 1; i <= columnCount; i++) {
                            String columnName = metaData.getColumnName(i);
                            Object columnValue = rs.getObject(i);
                            instance.set(columnName, columnValue);
                        }
                        jsonArray.set(instance);
                    }
                    result.set(outVarCode, jsonArray);
                } else {
                    result.set(outVarCode, object);
                }
            }
            stepLog.setSuccessFlag(true);
        } catch (Exception e) {
            log.error("存储过程执行失败", e);
            throw new ServiceException("存储过程执行失败");
        } finally {
            stepLog.setFinishFlag(true);
            DbUtil.close(resultSet, callableStatement, connection);
        }
        return result;
    }

    /*
    private JSONObject execProcedure(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo, HomeFlowSource homeFlowSource) {
        HomeFlowSourceBo.TypeEnum typeEnum = HomeFlowSourceBo.TypeEnum.getEnumByCode(homeFlowSource.getType());
        switch (typeEnum) {
            case ORACLE:
                return execOracleProcedure(homeFlowTaskStepExecBo, homeFlowSource);
            case MYSQL:
                return execMysqlProcedure(homeFlowTaskStepExecBo, homeFlowSource);
            case SQL_SERVER:
                // todo
                throw new ServiceException("当前数据库暂未适配");
            case GAUSS:
                return execGaussProcedure(homeFlowTaskStepExecBo, homeFlowSource);
            default:
                throw new ServiceException("当前数据库暂未适配");
        }
    }

    private JSONObject execOracleProcedure(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo, HomeFlowSource homeFlowSource) {
        HomeFlowTaskStepBo homeFlowTaskStepBo = homeFlowTaskStepExecBo.getHomeFlowTaskStepBo();
        JSONObject result = new JSONObject();
        DruidPooledConnection connection = null;
        CallableStatement callableStatement = null;
        ResultSet resultSet = null;
        VelocityUtils.VelocityResult velocityResult = VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqTemplate(), homeFlowTaskStepExecBo.getParamMap(), true);
        String maskTemplate = velocityResult.getTemplate();
        List<Object> varValueList = velocityResult.getVarValueList();
        HomeFlowTaskExecTaskStepLogVo stepLog = homeFlowTaskStepExecBo.getStepLog();
        HomeFlowTaskExecTaskStepLogVo.ExecContent execContent = stepLog.getExecContent();
        execContent.setStepType(homeFlowTaskStepBo.getStepType());
        execContent.setReqMethod(homeFlowTaskStepBo.getReqMethod());
        execContent.setReqTemplate(maskTemplate);
        for (Object object : varValueList) {
            if (object instanceof String) {
                execContent.setReqTemplate(execContent.getReqTemplate().replaceFirst("\\?", "'" + object + "'"));
            } else {
                execContent.setReqTemplate(execContent.getReqTemplate().replaceFirst("\\?", String.valueOf(object)));
            }
        }
        try {
            connection = DbUtils.getConnection(homeFlowSource);
            String owner = homeFlowSource.getUsername().trim().toUpperCase();
            String splitChar = "/";
            String procedure = maskTemplate;
            if (maskTemplate.contains(splitChar)) {
                owner = maskTemplate.split(splitChar)[0].trim().toUpperCase();
                maskTemplate = maskTemplate.split(splitChar)[1];
                procedure = owner + "." + maskTemplate;
            }
            callableStatement = connection.prepareCall("{call " + procedure + "}");
            String procedureName = maskTemplate.substring(0, maskTemplate.indexOf("(")).trim().toUpperCase();
            String packageName = null;
            String[] split = procedureName.split("\\.");
            StringBuilder sqlSb = new StringBuilder("SELECT * FROM ALL_ARGUMENTS WHERE OBJECT_NAME = ? and OWNER = ? ");
            if (split.length == 1) {
                sqlSb.append("and PACKAGE_NAME IS NULL ");
            } else if (split.length == 2) {
                packageName = split[0];
                procedureName = split[1];
                sqlSb.append("and PACKAGE_NAME = ? ");
            } else {
                throw new ServiceException("存储过程名称格式错误");
            }
            sqlSb.append("ORDER BY POSITION");
            PreparedStatement preparedStatement = connection.prepareStatement(sqlSb.toString());
            preparedStatement.setString(1, procedureName);
            preparedStatement.setString(2, owner);
            if (StringUtils.isNotBlank(packageName)) {
                preparedStatement.setString(3, packageName);
            }
            ResultSet procArgsRs = preparedStatement.executeQuery();
            List<String> outVarCodeList = new ArrayList<>();
            while (procArgsRs.next()) {
                String argName = procArgsRs.getString("ARGUMENT_NAME");
                int argPosition = procArgsRs.getInt("POSITION");
                String argMode = procArgsRs.getString("IN_OUT");
                String argDataType = procArgsRs.getString("DATA_TYPE");
                String argPackageName = procArgsRs.getString("PACKAGE_NAME");
                if (Objects.equals(packageName, argPackageName)) {
                    if (argMode.contains("IN")) {
                        Object object = null;
                        try {
                            object = varValueList.get(argPosition - 1);
                            DbUtils.containsSqlInjection(object);
                        } catch (Exception ignored) {
                        }
                        callableStatement.setObject(argName, object);
                    }
                    if (argMode.contains("OUT")) {
                        callableStatement.registerOutParameter(argName, DbUtils.getOracleDataType(argDataType));
                        outVarCodeList.add(argName);
                    }
                }
            }
            preparedStatement.close();
            callableStatement.execute();
            for (String outVarCode : outVarCodeList) {
                Object object = callableStatement.getObject(outVarCode);
                if (object instanceof ResultSet) {
                    ResultSet rs = (ResultSet) object;
                    ResultSetMetaData metaData = rs.getMetaData();
                    int columnCount = metaData.getColumnCount();
                    JSONArray jsonArray = new JSONArray();
                    while (rs.next()) {
                        JSONObject instance = new JSONObject();
                        for (int i = 1; i <= columnCount; i++) {
                            String columnName = metaData.getColumnName(i);
                            Object columnValue = rs.getObject(i);
                            instance.set(columnName, columnValue);
                        }
                        jsonArray.set(instance);
                    }
                    result.set(outVarCode, jsonArray);
                } else {
                    result.set(outVarCode, object);
                }
            }
            stepLog.setSuccessFlag(true);
        } catch (Exception e) {
            log.error("ORACLE存储过程执行失败", e);
            throw new ServiceException("ORACLE存储过程执行失败", e);
        } finally {
            stepLog.setFinishFlag(true);
            DbUtil.close(resultSet, callableStatement, connection);
        }
        return result;
    }

    private JSONObject execMysqlProcedure(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo, HomeFlowSource homeFlowSource) {
        HomeFlowTaskStepBo homeFlowTaskStepBo = homeFlowTaskStepExecBo.getHomeFlowTaskStepBo();
        JSONObject result = new JSONObject();
        DruidPooledConnection connection = null;
        CallableStatement callableStatement = null;
        ResultSet resultSet = null;
        VelocityUtils.VelocityResult velocityResult = VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqTemplate(), homeFlowTaskStepExecBo.getParamMap(), true);
        String maskTemplate = velocityResult.getTemplate();
        List<Object> varValueList = velocityResult.getVarValueList();
        HomeFlowTaskExecTaskStepLogVo stepLog = homeFlowTaskStepExecBo.getStepLog();
        HomeFlowTaskExecTaskStepLogVo.ExecContent execContent = stepLog.getExecContent();
        execContent.setStepType(homeFlowTaskStepBo.getStepType());
        execContent.setReqMethod(homeFlowTaskStepBo.getReqMethod());
        execContent.setReqTemplate(maskTemplate);
        for (Object object : varValueList) {
            if (object instanceof String) {
                execContent.setReqTemplate(execContent.getReqTemplate().replaceFirst("\\?", "'" + object + "'"));
            } else {
                execContent.setReqTemplate(execContent.getReqTemplate().replaceFirst("\\?", String.valueOf(object)));
            }
        }
        try {
            connection = DbUtils.getConnection(homeFlowSource);
            callableStatement = connection.prepareCall("{call " + maskTemplate + "}");
            StringBuilder sqlSb = new StringBuilder("SELECT * FROM information_schema.PARAMETERS WHERE SPECIFIC_NAME = ? and SPECIFIC_SCHEMA = ? ORDER BY ORDINAL_POSITION");
            PreparedStatement preparedStatement = connection.prepareStatement(sqlSb.toString());
            String pkgProcName = maskTemplate.substring(0, maskTemplate.indexOf("(")).trim().toUpperCase();
            preparedStatement.setString(1, pkgProcName);
            preparedStatement.setString(2, connection.getCatalog());
            ResultSet procArgsRs = preparedStatement.executeQuery();
            List<String> outVarCodeList = new ArrayList<>();
            while (procArgsRs.next()) {
                String argName = procArgsRs.getString("PARAMETER_NAME");
                int argPosition = procArgsRs.getInt("ORDINAL_POSITION");
                String argMode = procArgsRs.getString("PARAMETER_MODE");
                String argDataType = procArgsRs.getString("DATA_TYPE");
                if (argMode.contains("IN")) {
                    Object object = varValueList.get(argPosition - 1);
                    DbUtils.containsSqlInjection(object);
                    callableStatement.setObject(argName, object);
                }
                if (argMode.contains("OUT")) {
                    callableStatement.registerOutParameter(argName, MysqlType.getByName(argDataType).getJdbcType());
                    outVarCodeList.add(argName);
                }
            }
            preparedStatement.close();
            callableStatement.execute();
            for (String outVarCode : outVarCodeList) {
                Object object = callableStatement.getObject(outVarCode);
                if (object instanceof ResultSet) {
                    ResultSet rs = (ResultSet) object;
                    ResultSetMetaData metaData = rs.getMetaData();
                    int columnCount = metaData.getColumnCount();
                    JSONArray jsonArray = new JSONArray();
                    while (rs.next()) {
                        JSONObject instance = new JSONObject();
                        for (int i = 1; i <= columnCount; i++) {
                            String columnName = metaData.getColumnName(i);
                            Object columnValue = rs.getObject(i);
                            instance.set(columnName, columnValue);
                        }
                        jsonArray.set(instance);
                    }
                    result.set(outVarCode, jsonArray);
                } else {
                    result.set(outVarCode, object);
                }
            }
            stepLog.setSuccessFlag(true);
        } catch (Exception e) {
            log.error("MYSQL存储过程执行失败", e);
            throw new ServiceException("MYSQL存储过程执行失败", e);
        } finally {
            stepLog.setFinishFlag(true);
            DbUtil.close(resultSet, callableStatement, connection);
        }
        return result;
    }

     */

    private Object execApi(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo, HomeFlowSource homeFlowSource) {
        HomeFlowTaskStepBo homeFlowTaskStepBo = homeFlowTaskStepExecBo.getHomeFlowTaskStepBo();
        HomeFlowTaskStepBo.ReqMethodEnum reqMethodEnum = HomeFlowTaskStepBo.ReqMethodEnum.getEnumByCode(homeFlowTaskStepBo.getReqMethod());
        Map<String, Object> context = new HashMap<>();
        context.put("flowSource", homeFlowSource);
        Map<String, Object> flowParamMap = homeFlowTaskStepExecBo.getParamMap();
        if (!flowParamMap.isEmpty()) {
            context.putAll(flowParamMap);
        }
        VelocityUtils.VelocityResult vrAddress = VelocityUtils.processTemplate(homeFlowSource.getAddress(), context, true);
        String logAddress = VelocityUtils.getMaskLogStr(vrAddress);
        homeFlowSource.setAddress(VelocityUtils.processTemplate(homeFlowSource.getAddress(), context, false).getTemplate());
        VelocityUtils.VelocityResult vrReqTemplate = VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqTemplate(), context, true);
        String logReqTemplate = VelocityUtils.getMaskLogStr(vrReqTemplate);
        homeFlowTaskStepBo.setReqTemplate(VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqTemplate(), context, false).getTemplate());
        VelocityUtils.VelocityResult vrReqForm = VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqForm(), context, true);
        String logReqForm = VelocityUtils.getMaskLogStr(vrReqForm);
        homeFlowTaskStepBo.setReqForm(VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqForm(), context, false).getTemplate());
        VelocityUtils.VelocityResult vrReqBody = VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqBody(), context, true);
        String logReqBody = VelocityUtils.getMaskLogStr(vrReqBody);
        homeFlowTaskStepBo.setReqBody(VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqBody(), context, false).getTemplate());
        VelocityUtils.VelocityResult vrReqHeader = VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqHeader(), context, true);
        String logReqHeader = VelocityUtils.getMaskLogStr(vrReqHeader);
        homeFlowTaskStepBo.setReqHeader(VelocityUtils.processTemplate(homeFlowTaskStepBo.getReqHeader(), context, false).getTemplate());
        HomeFlowTaskExecTaskStepLogVo stepLog = homeFlowTaskStepExecBo.getStepLog();
        HomeFlowTaskExecTaskStepLogVo.ExecContent execContent = stepLog.getExecContent();
        execContent.setStepType(homeFlowTaskStepBo.getStepType());
        execContent.setAddress(logAddress);
        execContent.setReqMethod(homeFlowTaskStepBo.getReqMethod());
        execContent.setReqTemplate(logReqTemplate);
        execContent.setReqForm(logReqForm);
        execContent.setReqBody(logReqBody);
        execContent.setReqHeader(logReqHeader);
        String reqContentType = homeFlowTaskStepBo.getReqContentType();
        HomeFlowTaskStepBo.ReqContentTypeEnum reqContentTypeEnum = HomeFlowTaskStepBo.ReqContentTypeEnum.getEnumByCode(reqContentType);
        if (Objects.nonNull(reqContentTypeEnum)) {
            reqContentType = reqContentTypeEnum.getDesc();
        }
        execContent.setReqContentType(reqContentType);
        Object resp;
        if (Objects.equals(reqMethodEnum, HomeFlowTaskStepBo.ReqMethodEnum.WEB_SERVICE)) {
            // WebService请求
            Client client = null;
            try {
                Bus bus = BusFactory.newInstance().createBus();
                bus.setProperty("disable.selectors.cache", Boolean.TRUE);  // 关闭选择器缓存
                bus.setProperty("org.apache.cxf.wsdl.disableCache", Boolean.TRUE);
                JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
                client = dcf.createClient(homeFlowSource.getAddress());
                if (Objects.isNull(client)) {
                    throw new ServiceException("CXF客户端实例为空");
                }
                // 获取 CXF 客户端实例并添加日志拦截器
                client.getInInterceptors().add(new LoggingInInterceptor());
                client.getOutInterceptors().add(new LoggingOutInterceptor());
                JSONObject jsonObject = JSONUtil.parseObj(homeFlowTaskStepBo.getReqTemplate());
                Map<String, List<Object>> cxfHttpHeadersMap = new HashMap<>();
                try {
                    String httpHeaders = homeFlowTaskStepBo.getReqHeader();
                    if (StringUtils.isNotBlank(httpHeaders)) {
                        Map<String, Object> map = JSONUtil.toBean(
                                httpHeaders,
                                new TypeReference<Map<String, Object>>() {
                                },
                                false
                        );
                        if (!map.isEmpty()) {
                            for (String key : map.keySet()) {
                                Object value = map.get(key);
                                if (ObjectUtils.isNotEmpty(key) && ObjectUtils.isNotEmpty(value)) {
                                    cxfHttpHeadersMap.put(key, Collections.singletonList(value));
                                }
                            }
                        }
                    }
                    JSONObject headers = jsonObject.getJSONObject("headers");
                    if (Objects.nonNull(headers)) {
                        for (String key : headers.keySet()) {
                            Object object = headers.get(key);
                            if (object instanceof JSONArray) {
                                JSONArray jsonArray = (JSONArray) object;
                                cxfHttpHeadersMap.put(key, jsonArray);
                            } else {
                                cxfHttpHeadersMap.put(key, Collections.singletonList(object));
                            }
                        }
                    }
                    if (!cxfHttpHeadersMap.isEmpty()) {
                        client.getRequestContext().put(Message.PROTOCOL_HEADERS, cxfHttpHeadersMap);
                    }
                } catch (Exception e) {
                    log.error("HTTP_HEADERS格式解析失败", e);
                    throw new ServiceException("HTTP_HEADERS格式解析失败");
                }
                try {
                    JSONObject headerJsonObj = jsonObject.getJSONObject("header");
                    if (Objects.nonNull(headerJsonObj)) {
                        Optional<String> first = client.getEndpoint().getService().getServiceInfos().stream().map(o -> o.getName().getNamespaceURI()).findFirst();
                        String ns = null;
                        if (first.isPresent()) {
                            ns = first.get();
                        }
                        if (ObjectUtils.isEmpty(ns)) {
                            throw new ServiceException("header格式解析失败，命名空间为空");
                        }
                        List<org.apache.cxf.headers.Header> headers = new ArrayList<>();
                        for (String node : headerJsonObj.keySet()) {
                            Element element = DOMUtils.createDocument().createElementNS(ns, node.trim());
                            Document doc = element.getOwnerDocument(); // 获取属于该元素的文档对象
                            JSONObject nodes = headerJsonObj.getJSONObject(node);
                            for (String key : nodes.keySet()) {
                                Element child = doc.createElementNS(ns, key.trim());
                                child.setTextContent(nodes.getStr(key));
                                element.appendChild(child);
                            }
                            QName headerName = new QName(ns, node.trim());
                            org.apache.cxf.headers.Header header = new org.apache.cxf.headers.Header(headerName, element);
                            headers.add(header);
                            client.getRequestContext().put(org.apache.cxf.headers.Header.HEADER_LIST, headers);
                        }
                    }
                } catch (Exception e) {
                    log.error("header格式解析失败", e);
                    throw new ServiceException("header格式解析失败");
                }
                HTTPConduit conduit = (HTTPConduit) client.getConduit();
                HTTPClientPolicy policy = new HTTPClientPolicy();
                policy.setConnectionTimeout(60000);  // 连接超时 60 秒
                policy.setReceiveTimeout(60000);     // 接收超时 60 秒
                policy.setCacheControl("no-cache");
                conduit.setClient(policy);
                String operationName = jsonObject.getStr("operationName");
                if (StringUtils.isBlank(operationName)) {
                    throw new ServiceException("缺少属性operationName，或operationName的值为空");
                }
                Object[] respArr;
                List<Object> paramList = new ArrayList<>();
                Object argsObj = jsonObject.get("args");
                if (argsObj instanceof JSONArray) {
                    JSONArray jsonArray = (JSONArray) argsObj;
                    paramList.addAll(jsonArray);
                } else {
                    JSONObject args = (JSONObject) argsObj;
                    if (Objects.nonNull(args)) {
                        List<Integer> keyNoList = args.keySet().stream()
                                .map(Integer::valueOf)
                                .sorted(Comparator.naturalOrder())
                                .collect(Collectors.toList());
                        for (Integer keyNo : keyNoList) {
                            Object object = args.get(String.valueOf(keyNo));
                            if (object instanceof String) {
                                String valueStr = String.valueOf(object);
                                if (StringUtils.isNotBlank(valueStr)) {
                                    valueStr = valueStr.toLowerCase().trim();
                                    if (valueStr.startsWith("(short)")) {
                                        paramList.add(Short.valueOf(valueStr.replaceFirst("\\(short\\)", "").trim()));
                                        continue;
                                    }
                                    if (valueStr.startsWith("(int)")) {
                                        paramList.add(Integer.valueOf(valueStr.replaceFirst("\\(int\\)", "").trim()));
                                        continue;
                                    }
                                    if (valueStr.startsWith("(long)")) {
                                        paramList.add(Long.valueOf(valueStr.replaceFirst("\\(long\\)", "").trim()));
                                        continue;
                                    }
                                    if (valueStr.startsWith("(double)")) {
                                        paramList.add(Double.valueOf(valueStr.replaceFirst("\\(double\\)", "").trim()));
                                        continue;
                                    }
                                    if (valueStr.startsWith("(decimal)")) {
                                        paramList.add(new BigDecimal(valueStr.replaceFirst("\\(decimal\\)", "").trim()));
                                        continue;
                                    }
                                    if (valueStr.startsWith("(bigdecimal)")) {
                                        paramList.add(new BigDecimal(valueStr.replaceFirst("\\(bigdecimal\\)", "").trim()));
                                        continue;
                                    }
                                    if (valueStr.startsWith("(date|")) {
                                        String subStr = valueStr.replaceFirst("\\(date\\|", "");
                                        String pattern = subStr.substring(0, subStr.indexOf(")"));
                                        String dateStr = subStr.substring(subStr.indexOf(")") + 1);
                                        Date date = DateUtils.stringToDate(dateStr, pattern);
                                        paramList.add(date);
                                        continue;
                                    }
                                }
                            }
                            paramList.add(object);
                        }
                    }
                }
                respArr = client.invoke(operationName, paramList.toArray(new Object[0]));
                resp = respArr[0];
            } catch (Exception e) {
                log.error("WebService请求异常", e);
                throw new ServiceException("WebService请求异常");
            } finally {
                if (Objects.nonNull(client)) {
                    client.destroy();
                }
            }
        } else {
            Map<String, String> httpHeadersMap = new HashMap<>();
            try {
                String httpHeaders = homeFlowTaskStepBo.getReqHeader();
                if (StringUtils.isNotBlank(httpHeaders)) {
                    Map<String, String> map = JSONUtil.toBean(
                            httpHeaders,
                            new TypeReference<Map<String, String>>() {
                            },
                            false
                    );
                    if (!map.isEmpty()) {
                        for (String key : map.keySet()) {
                            String value = map.get(key);
                            if (ObjectUtils.isNotEmpty(key) && ObjectUtils.isNotEmpty(value)) {
                                httpHeadersMap.put(key, value);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("HTTP_HEADERS格式解析失败", e);
                throw new ServiceException("HTTP_HEADERS格式解析失败");
            }
            HttpRequest httpRequest;
            if (Objects.equals(reqMethodEnum, HomeFlowTaskStepBo.ReqMethodEnum.GET)) {
                if (!Objects.equals(reqContentType, HomeFlowTaskStepBo.ReqContentTypeEnum.FORM_URLENCODED.getDesc())) {
                    throw new ServiceException("ContentType不支持");
                }
                Map<String, Object> reqFormMap = new HashMap<>();
                try {
                    String reqForm = homeFlowTaskStepBo.getReqForm();
                    if (StringUtils.isNotBlank(reqForm)) {
                        HashMap<String, Object> map = JSONUtil.toBean(
                                reqForm,
                                new TypeReference<HashMap<String, Object>>() {
                                },
                                false
                        );
                        if (!map.isEmpty()) {
                            reqFormMap = map;
                        }
                    }
                } catch (Exception e) {
                    log.error("REQ_PARAMS格式解析失败", e);
                    throw new ServiceException("REQ_PARAMS格式解析失败");
                }
                httpRequest = HttpRequest.get(homeFlowSource.getAddress()).form(reqFormMap).addHeaders(new HashMap<String, String>() {{
                    put(Header.CONTENT_TYPE.getValue(), ContentType.FORM_URLENCODED.getValue() + ";charset=UTF-8");
                }});
            } else if (Objects.equals(reqMethodEnum, HomeFlowTaskStepBo.ReqMethodEnum.POST)) {
                String address = homeFlowSource.getAddress();
                try {
                    String reqForm = homeFlowTaskStepBo.getReqForm();
                    if (StringUtils.isNotBlank(reqForm)) {
                        UrlBuilder urlBuilder = UrlBuilder.of(address);
                        // 添加新参数
                        HashMap<String, Object> newParams = JSONUtil.toBean(reqForm, new TypeReference<HashMap<String, Object>>() {
                        }, false);
                        for (Map.Entry<String, Object> entry : newParams.entrySet()) {
                            urlBuilder.addQuery(entry.getKey(), entry.getValue());
                        }
                        address = urlBuilder.build();
                    }
                } catch (Exception e) {
                    throw new ServiceException("请求表单配置JSON格式不正确");
                }
                if (Objects.equals(reqContentType, HomeFlowTaskStepBo.ReqContentTypeEnum.JSON.getDesc())) {
                    String reqBody = homeFlowTaskStepBo.getReqBody();
                    try {
                        if (StringUtils.isNotBlank(reqBody)) {
                            JSONObject jsonObject = JSONUtil.parseObj(reqBody);
                            reqBody = JSONUtil.toJsonStr(jsonObject);
                        }
                    } catch (Exception e) {
                        throw new ServiceException("请求体配置JSON格式不正确");
                    }
                    httpRequest = HttpRequest.post(address).body(reqBody);
                } else if (Objects.equals(reqContentType, HomeFlowTaskStepBo.ReqContentTypeEnum.TEXT_PLAIN.getDesc())) {
                    httpRequest = HttpRequest.post(address).body(homeFlowTaskStepBo.getReqBody(), ContentType.TEXT_PLAIN.getValue() + ";charset=UTF-8");
                } else {
                    httpRequest = HttpRequest.post(address).body(homeFlowTaskStepBo.getReqBody(), reqContentType);
                }
            } else {
                throw new ServiceException("接口类型未实现");
            }
            if (!httpHeadersMap.isEmpty()) {
                httpRequest = httpRequest.addHeaders(httpHeadersMap);
            }
            HttpResponse httpResponse = httpRequest
                    .timeout(60000)
                    .execute();
            int status = httpResponse.getStatus();
            resp = httpResponse.body();
            if (status != 200) {
                throw new ServiceException("HTTP请求失败，状态码：" + status + "。响应内容：" + resp);
            }
        }
        stepLog.setSuccessFlag(true);
        stepLog.setFinishFlag(true);
        return resp;
    }

    private Object execBean(HomeFlowTaskStepExecBo homeFlowTaskStepExecBo) {
        HomeFlowTaskStepBo homeFlowTaskStepBo = homeFlowTaskStepExecBo.getHomeFlowTaskStepBo();
        Map<String, Object> flowParamMap = homeFlowTaskStepExecBo.getParamMap();
        String reqTemplate = homeFlowTaskStepBo.getReqTemplate();
        homeFlowTaskStepBo.setReqTemplate(VelocityUtils.processTemplate(reqTemplate, flowParamMap, false).getTemplate());
        HomeFlowTaskExecTaskStepLogVo stepLog = homeFlowTaskStepExecBo.getStepLog();
        stepLog.setReqParamMap(flowParamMap);
        HomeFlowTaskExecTaskStepLogVo.ExecContent execContent = stepLog.getExecContent();
        execContent.setStepType(homeFlowTaskStepBo.getStepType());
        execContent.setReqMethod(homeFlowTaskStepBo.getReqMethod());
        execContent.setReqTemplate(homeFlowTaskStepBo.getReqTemplate());
        Object resp;
        try {
            String clazzName = reqTemplate.substring(0, reqTemplate.lastIndexOf("."));
            String methodStr = reqTemplate.substring(reqTemplate.lastIndexOf(".") + 1);
            Object bean = SpringUtils.getBean(Class.forName(clazzName));
            Method method = Class.forName(clazzName).getMethod(methodStr, Map.class);
            resp = method.invoke(bean, flowParamMap);
            stepLog.setSuccessFlag(true);
        } catch (Exception e) {
            throw new ServiceException("执行JavaBean失败");
        } finally {
            stepLog.setFinishFlag(true);
        }
        return resp;
    }

    @Override
    public String getRedisKeyFlowExecTask(String taskCode) {
        return "home:flow:execTask:" + taskCode + ":" + SecurityUtils.getUserId();
    }

    @Override
    public List<HomeFlowTaskStep> listByTaskCodeAndStepCode(String taskCode, String stepCode) {
        return this.list(new LambdaQueryWrapper<HomeFlowTaskStep>() {{
            eq(HomeFlowTaskStep::getTaskCode, taskCode);
            eq(HomeFlowTaskStep::getStepCode, stepCode);
        }});
    }
}





